#pragma once

#include "MBDataTypes.h"
#include <map>
#include <set>
#include <string>
#include <vector>

//OpenCV
#include <opencv2/opencv.hpp>

/**
  *	An MBImagePathWithMemoryConsumption object capsules an image path and the
  * memory consumption of the uncompressed image in bytes inside memory
  *
  */
struct MBImagePathWithMemoryConsumption
{
	/**
	  * Constructs a new MBImagePathWithMemoryConsumption object
	  *
	  * @param imagePath full path of the image file
	  * @param memoryConsumption memory consumption of the uncompressed image in bytes inside memory
	  */
	MBImagePathWithMemoryConsumption( const std::string &imagePath, const MBuint &memoryConsumption ) :
		mImagePath( imagePath ),
		mMemoryConsumption( memoryConsumption ) {};
	/** Full path of the image file */
	std::string mImagePath;
	/** Memory consumption of the uncompressed image in bytes inside memory */
	MBuint mMemoryConsumption;
};

/**
  *	The MBImageManager is responsible for the loading and unloading of images.
  * It only consumes as much memory as set with the
  * SetMaximumMemoryConsumptionInBytes() method. When the loading of an image
  * would exceed the maximum memory consumption, the image, that was loaded the
  * longest time ago, is unloaded.
  */
class MBImageManager
{
public:
	void FreeAllImages( void );
	MBuint FreeImage( const std::string &imagePath );
	static MBImageManager &Get( void );
	const cv::Mat *GetImage(
		const std::string &imagePath,
		const MBuint layerNumber = 0,
		const std::set<std::string> *untouchableImagePaths = 0 );

	MBuint GetNumberOfLoadedImages( void ) const;
	double GetTimeInSecondsUsedForImageLoading( void ) const;

	void ResetNumberOfLoadedImages( void );
	void ResetTimeNeededForLoading( void );

	void SetExclusiveLevel( const MBuint &exclusiveLevel );
	void SetMaximumMemoryConsumptionInBytes( const MBuint &maxMemoryConsumption );

private:
	MBImageManager( void );
	~MBImageManager( void );
	/** The image manager himself */
	static MBImageManager *imageManager;
	
	/** Maximum consumption of all images in memory in bytes */
	MBuint mMaxMemoryConsumption;
	/** Current memory consumption of the images in bytes */
	MBuint mCurrentMemoryConsumption;
	/** Number, that is increased by 1 after every image loading, to rank the loaded images */
	MBuint mCurrentImageOrder;
	/** Exclusive mipmap level of all loaded images */
	MBuint mExclusiveLevel;

	/** Map, that maps image paths to their rank number */
	std::map<std::string, MBuint> mImagePathToCurrentOrderMap;
	/** Map, that maps rank numbers to the corresponding MBImagePathWithMemoryConsumption object */
	std::map<MBuint, MBImagePathWithMemoryConsumption> mCurrentOrderToImagePathMap;
	/** Map, that maps image paths to their image pyramid */
	std::map<std::string, std::vector<cv::Mat*>> mImagePathToImagePyramidMap;

	/** Accumulative number of image files that were loaded */
	MBuint mNumImagesLoaded;
	/** Accumulative time in seconds that was used to load image files */
	double mSecondsNeededForLoading;
};